﻿using System;
using System.Collections;
using System.Collections.Generic;
using System.Text;
using System.Threading;
using System.ComponentModel;
using System.IO;
using System.Data;
using System.Linq;

namespace Txt2PajekLarge
{
    class DataLoader
    {
        private string strFileName = "";
        private char cSplitter = '\t';
        private bool blnAsyncCancelled = true;
        //private string strProcessMessage = "Starting Data Loader...";          //日志内容
        private bool blnSuspending = false;         //是否暂停，默认为“否”
        private BackgroundWorker oAsyncWorker = null;
        private double weight = 1;
        private int nSleepTime = 1;

        #region properties

        public string FileName
        {
            get { return strFileName; }
            set { strFileName = value; }
        }

        public bool AsyncCancelled
        {
            set { blnAsyncCancelled = value; }
            get { return blnAsyncCancelled; }
        }

        public bool Suspending
        {
            get { return blnSuspending; }
            set { blnSuspending = value; }
        }

        public BackgroundWorker AsyncWorker
        { set { oAsyncWorker = value; } }

        //public string ProcessMessage
        //{ get { return strProcessMessage; } }

        #endregion
        public DataLoader() { }

        public DataLoader(string FileName)
        {
            strFileName = FileName;
        }

        private void LoadToMem(string strFilePath)
        {
            //建立一个LinkedList存储txt文件中的数据
            BigDictionary<string, long> dicNodeBuffer = new BigDictionary<string, long>();
            BigDictionary<Edge, long> dicEdgeBuffer = new BigDictionary<Edge, long>();
            long i = 0, j = 0;
            oAsyncWorker.ReportProgress(0,"Starting loading data...");
            Thread.Sleep(nSleepTime);
            //读入文件
            using (StreamReader reader = new StreamReader(strFilePath, Encoding.Default))
            {
                try
                {
                    while (!reader.EndOfStream)
                    {
                        while (blnSuspending)    //pause
                        {
                            if (blnAsyncCancelled)
                            {
                                blnAsyncCancelled = true;
                                blnSuspending = false;

                                reader.Close();
                                reader.Dispose();

                                return;
                            }
                            Thread.Sleep(50);
                        }

                        string strOneLine = reader.ReadLine();
                        if (strOneLine.StartsWith("#") || strOneLine.StartsWith("*")) continue;
                        string[] strLine = strOneLine.Split(cSplitter);
                        if (GlobalPool.Settings.Ignore1stLine) strLine = reader.ReadLine().Split(cSplitter);

                        //查找重复的数据
                        if (GlobalPool.Settings.WeightOnEdge) weight = Convert.ToDouble(strLine[2]);
                        else weight = 1;
                        if (!dicNodeBuffer.ContainsKey(strLine[0]))
                        {
                            i = dicNodeBuffer.Count + GlobalPool.Settings.NodeIDStartFrom;
                            dicNodeBuffer.Add(strLine[0], i);
                            GlobalPool.NodeList.Add(new Node(i, strLine[0]));
                        }
                        else
                            i = dicNodeBuffer[strLine[0]];

                        if (!dicNodeBuffer.ContainsKey(strLine[1]))
                        {
                            j = dicNodeBuffer.Count + GlobalPool.Settings.NodeIDStartFrom;
                            dicNodeBuffer.Add(strLine[1], j);                            
                            GlobalPool.NodeList.Add(new Node(j, strLine[1]));
                        }
                        else
                            j = dicNodeBuffer[strLine[1]];

                        Edge edge = new Edge(i, j, weight);
                        if(!dicEdgeBuffer.ContainsKey(edge))
                        {
                            dicEdgeBuffer.Add(edge,0);
                            GlobalPool.EdgeList.Add(edge);
                        }
                        if ((dicNodeBuffer.Count & 16383) == 0 || (dicEdgeBuffer.Count & 16383) == 0)
                        {
                            oAsyncWorker.ReportProgress(0, "There have been " + dicNodeBuffer.Count.ToString() + " vertices and " + dicEdgeBuffer.Count.ToString() + " edges.");
                            Thread.Sleep(nSleepTime);
                        }
                    }//while
                    GlobalPool.NodeList.CompleteAdding();
                    GlobalPool.EdgeList.CompleteAdding();
                }
                catch (Exception ex)
                {
                    blnAsyncCancelled = true;
                    blnSuspending = false;
                    throw ex;
                }
                oAsyncWorker.ReportProgress(0, "There have been " + dicNodeBuffer.Count.ToString() + " vertices and " + dicEdgeBuffer.Count.ToString() + " edges.");
                Thread.Sleep(nSleepTime);
                return;
            }//using
        }

        private void LoadToDB(string strFilePath)
        {
            long lCntVertices = 0;
            long lCntEdges = 0;
            string strSQL = "";
            Database db = DatabaseFactory.CreateDatabase();

            //读入文件
            using (StreamReader reader = new StreamReader(strFilePath, Encoding.Default))
            {
                try
                {
                    while (!reader.EndOfStream)
                    {
                        while (blnSuspending)    //pause
                        {
                            if (blnAsyncCancelled)
                            {
                                blnAsyncCancelled = true;
                                blnSuspending = false;
                                lCntVertices = 0;
                                lCntEdges = 0;

                                return;
                            }
                            Thread.Sleep(50);
                        }
                        string strOneLine = reader.ReadLine();
                        if (strOneLine.StartsWith("#")) continue;
                        string[] strLine = strOneLine.Split(cSplitter);
                        if (GlobalPool.Settings.Ignore1stLine) strLine = reader.ReadLine().Split(cSplitter);

                        //查找重复的数据
                        if (GlobalPool.Settings.WeightOnEdge) weight = Convert.ToDouble(strLine[2]);

                        long i = 0, j = 0;
                        strSQL = "select v_id from " + GlobalPool.NODE_TABLE + " where label=" + strLine[0];
                        DataRow dr = db.GetDataRow(strSQL);
                        if (dr == null)   //there isn't
                        {
                            Hashtable ht = new Hashtable();
                            ht.Add("v_id", lCntVertices);
                            ht.Add("label", strLine[0]);
                            db.Insert(GlobalPool.NODE_TABLE, ht);
                            i = lCntVertices + GlobalPool.Settings.NodeIDStartFrom;
                            lCntVertices++;
                            GlobalPool.NodeList.Add(new Node(i, strLine[0]));
                        }
                        else
                            i = Convert.ToInt64(dr[0]);

                        strSQL = "select v_id from " + GlobalPool.NODE_TABLE + " where label=" + strLine[1];
                        dr = db.GetDataRow(strSQL);
                        if (dr == null)   //there isn't
                        {
                            Hashtable ht = new Hashtable();
                            ht.Add("v_id", lCntVertices);
                            ht.Add("label", strLine[1]);
                            db.Insert(GlobalPool.NODE_TABLE, ht);
                            j = lCntVertices + GlobalPool.Settings.NodeIDStartFrom;
                            lCntVertices++;
                            GlobalPool.NodeList.Add(new Node(j, strLine[1]));
                        }
                        else
                            j = Convert.ToInt64(dr[0]);

                        strSQL = "select count(*) from " + GlobalPool.ARC_TABLE + " where v_s=" + i.ToString() + " and v_t=" + j.ToString();
                        dr = db.GetDataRow(strSQL);
                        while (dr == null) dr = db.GetDataRow(strSQL);
                        if (Convert.ToInt32(dr[0]) == 0)
                        {
                            Hashtable ht = new Hashtable();
                            ht.Add("v_s", i);
                            ht.Add("v_t", j);
                            ht.Add("w", weight);
                            db.Insert(GlobalPool.ARC_TABLE, ht);
                            GlobalPool.EdgeList.Add(new Edge(i, j, weight));
                            lCntEdges++;
                        }
                        if ((lCntVertices & 16383) == 0 || (lCntEdges & 16383) == 0)
                        {
                            oAsyncWorker.ReportProgress(0, "There have been " + lCntVertices.ToString() + " vertices and " + lCntEdges.ToString() + " edges.");
                            Thread.Sleep(nSleepTime);
                        }
                    }//while 
                    oAsyncWorker.ReportProgress(0, "There have been " + lCntVertices.ToString() + " vertices and " + lCntEdges.ToString() + " edges.");
                    Thread.Sleep(nSleepTime);
                }
                catch (Exception ex)
                {
                    blnAsyncCancelled = true;
                    blnSuspending = false;
                    throw ex;
                }
                return;
            }
        }

        public void LoadData()
        {
            try
            {
                if (strFileName == null || strFileName.Trim() == "") return;

                switch (GlobalPool.Settings.Splitter)
                {
                    case SplitterChar.LINE:
                        cSplitter = '|';
                        break;
                    case SplitterChar.SPACE:
                        cSplitter = ' ';
                        break;
                    default:
                        cSplitter = '\t';
                        break;
                }

                blnAsyncCancelled = false;
                if (GlobalPool.Settings.BufferedIn == BufferIn.BUFFER_IN_MEM) LoadToMem(strFileName);
                else LoadToDB(strFileName);
            }
            catch
            {
                throw;
            }
            finally
            {
                blnAsyncCancelled = true;
                blnSuspending = false;
            }
        }
    }
}
